/*
 * QFontAdapter.cpp  0.4.0 / Nov 17, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "QFontAdapter.h"

#include "QApplicationDelegate.h"
#include "SwingString.h"
#include "SwingUtilitiesDelegate.h"
#include "JNISwingWrapper.h"

// QFontAdapter :: Protected Constructor. --------------------------------------

/*!
 * \brief Constructs new QFontAdapter object.
 *
 * \param name the font name
 * \param style the font style
 * \param size the font size
 */
QFontAdapter::QFontAdapter(jstring name, jint style, jint size)
  : QFont(SwingString(name), size)
{
  if (style & 0x1) {
    setBold(true);
  }
  if (style & 0x2) {
    setItalic(true);
  }
  if (style & 0x4) {
    setUnderline(true);
  }
  if (style & 0x8) {
    setOverline(true);
  }
  if (style & 0x10) {
    setStrikeOut(true);
  }
}

/*!
 * \brief Constructs new QFontAdapter object.
 *
 * \param font the font
 */
QFontAdapter::QFontAdapter(const QFont &font)
  : QFont(font)
{
  // empty body
}

// QFontAdapter :: Public Static Member Functions. -----------------------------

/*!
 * \brief Initializes QFontAdapter class.
 *
 * \param env the JNIEnv pointer
 * \param cls the Swing font class
 *
 * \exception FatalError if failed
 */
void QFontAdapter::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_fontClass);
  if (!INIT_CLASS(font, cls) || !INIT_FID(lock, cls, "Ljava/lang/Object;") ||
      !INIT_CONSTRUCTOR(constructor, cls, "(Ljava/lang/String;IIJ)V")||
      !INIT_UMID(create, cls, "(Ljava/lang/String;II)J") ||
      !INIT_UMID(createFontMetrics, cls, "(J)J") ||
      !INIT_UMID(getFontPointer, cls, "()J")) {
    FATAL_LOGGED_ERROR("QFontAdapter initialization failed");
  }
}

/*!
 * \brief Returns QFontAdapter instance.
 *
 * \param env the JNIEnv pointer
 * \param font the Swing font object
 *
 * \return FontAdapter instance
 */
QFontAdapter *QFontAdapter::toQFont(JNIEnv *env, jobject font)
{
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
  LocalMonitor monitor(env, font, sm_lockFID);
  if (monitor.enter()) {
    jlong instance;
    if (JNIWrapper::callLongMethod(env, instance, font, sm_getFontPointerMID)) {
      return qFontCast(instance);
    }
  }
  return 0;
}

/*!
 * \brief Returns QFontAdapter instance.
 *
 * \param font the Swing font object
 *
 * \return FontAdapter instance
 */
QFontAdapter *QFontAdapter::toQFont(jobject font)
{
  Q_ASSERT(font);
  LocalMonitor monitor(JNISwingWrapper::env(), font, sm_lockFID);
  if (monitor.enter()) {
    jlong instance;
    if (JNISwingWrapper::callLongMethod(instance, font, sm_getFontPointerMID)) {
      return qFontCast(instance);
    }
  }
  return 0;
}

/*!
 * \brief Creates new Swing font instance.
 *
 * \param env the JNIEnv pointer
 * \param fontClass the Swing font class
 * \param font the QFont reference
 *
 * \return new Swing font instance
 *
 * \exception OutOfMemoryError java exception
 */
jobject QFontAdapter::toJFont(JNIEnv *env, jclass fontClass, const QFont &font)
{
  jstring fontName = QStringAdapter::toJString(env, font.family());
  if (!fontName) {
    return 0;  // out of memory
  }
  return JNIWrapper::newObject(env, fontClass, sm_constructorMID, fontName,
                               fontStyle(font), font.pointSize(),
                               reinterpret_cast<jlong>(new QFontAdapter(font)));
}

/*!
 * \brief Creates new Swing font instance.
 *
 * \param font the QFont reference
 *
 * \return new Swing font instance
 *
 * \exception OutOfMemoryError java exception
 */
jobject QFontAdapter::toJFont(const QFont &font)
{
  jstring fontName = SwingString::toJString(font.family());
  if (!fontName) {
    return 0;  // out of memory
  }
  return JNISwingWrapper::newObject(sm_fontClass, sm_constructorMID, fontName,
                                    fontStyle(font), font.pointSize(),
                                    reinterpret_cast<jlong>(
                                                      new QFontAdapter(font)));
}

// QFontAdapter :: Static Native Calls. ----------------------------------------

/*!
 * \brief Returns new instance of QFontAdapter class.
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing font class
 * \param name the font name
 * \param style the font style
 * \param size the font size
 *
 * \return new instance of QFontAdapter class
 */
jlong QFontAdapter::newInstance(JNIEnv *env, jobject obj, jstring name,
                                jint style, jint size)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new QFontAdapter(name, style, size));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, sm_createMID,
                                                   name, style, size);
} 

/*!
 * \brief Returns new instance of QFontMetrics class.
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing font object
 * \param fontPonter the font pointer
 *
 * \return new instance of QFontMetrics class
 */
jlong QFontAdapter::newFontMetricsInstance(JNIEnv *env, jobject obj,
                                           jlong fontPonter)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new QFontMetrics(*qFontAdapter));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj,
                                                   sm_createFontMetricsMID,
                                                   fontPonter);
}

/*!
 * \brief Returns the name of default font.
 *
 * \param env the JNIEnv pointer
 * \param cls the Swing font class
 *
 * \return the name of default font
 */
jstring QFontAdapter::getDefaultFontName(JNIEnv *env, jclass cls)
{
  Q_UNUSED(cls);
  return QStringAdapter::toJString(env, qAppAdapter->font().family());
}

// QFontAdapter :: Private Static Member Function. -----------------------------

jint QFontAdapter::fontStyle(const QFont &font)
{
  jint style = 0;
  if (font.bold()) {
    style |= 0x1;
  }
  if (font.italic()) {
    style |= 0x2;
  }
  if (font.underline()) {
    style |= 0x4;
  }
  if (font.overline()) {
    style |= 0x8;
  }
  if (font.strikeOut()) {
    style |= 0x10;
  }
  return style;
}

// QFontAdapter :: Private Static Data Members. --------------------------------

jclass QFontAdapter::sm_fontClass = 0;
jfieldID QFontAdapter::sm_lockFID = 0;
jmethodID QFontAdapter::sm_constructorMID = 0;
jmethodID QFontAdapter::sm_createMID = 0;
jmethodID QFontAdapter::sm_createFontMetricsMID = 0;
jmethodID QFontAdapter::sm_getFontPointerMID = 0;
